package com.digua.atools.tools;

import android.content.Context;
import android.widget.Toast;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

/**
 * @author:digua
 * @dat:2021/8/21
 * @description:数字工具
 */
public class NumUtil extends com.digua.atools.tools.IntUtil {
    /**
     * 比较两个数大小
     *
     * @param num1
     * @param num2
     * @return num1 > num2 => 1; num1 == num2 => 0; num1 < num2 => -1;
     */
    public static <T> int compare(T num1, T num2) {
        return compare(num1, num2, null);
    }


    /**
     * 获取非空值
     *
     * @param val    原值
     * @param defVal 默认值
     * @return 如没有默认值，val为空时返回：val；如果有默认值时，为空返回默认值
     */
    public static <T> T getVal(T val, T... defVal) {
        return val != null ? val : defVal == null || defVal.length <= 0 ? val : defVal[0];
    }

    /**
     * 比较两个数大小
     *
     * @param num1
     * @param num2
     * @param def  当有空值时返回地默认值， 传空时，null值方小
     * @return num1 > num2 => 1; num1 == num2 => 0; num1 < num2 => -1;
     */
    public static <T> int compare(T num1, T num2, Integer def) {
        if (num1 == null && num2 == null) {
            return 0;
        }
        if (num1 == null) {
            return def == null ? -1 : def;
        }
        if (num2 == null) {
            return def == null ? 1 : def;
        }
        BigDecimal n1 = BigDecimal.ZERO;
        BigDecimal n2 = BigDecimal.ZERO;
        try {
            n1 = new BigDecimal(num1.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            n2 = new BigDecimal(num2.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
        double val = n1.subtract(n2).doubleValue();
        return val > 0 ? 1 : val < 0 ? -1 : 0;
    }

    /**
     * 比较两个数是否相等
     *
     * @param num1
     * @param num2
     * @return
     */
    public static <T> boolean eq(T num1, T num2) {
        return compare(num1, num2) == 0;
    }

    /**
     * 比较num1是否大于num2
     *
     * @param num1
     * @param num2
     * @return num1 > num2
     */
    public static <T> boolean gt(T num1, T num2) {
        return compare(num1, num2) > 0;
    }

    /**
     * 比较num1是否大于等于num2
     *
     * @param num1
     * @param num2
     * @return
     */
    public static <T> boolean gte(T num1, T num2) {
        return compare(num1, num2) >= 0;
    }

    /**
     * 比较num1是否小于num2
     *
     * @param num1
     * @param num2
     * @return
     */
    public static <T> boolean lt(T num1, T num2) {
        return compare(num1, num2) < 0;
    }

    /**
     * 比较num1是否小于等于num2
     *
     * @param num1
     * @param num2
     * @return
     */
    public static <T> boolean lte(T num1, T num2) {
        return compare(num1, num2) <= 0;
    }

    /**
     * 比较两个数是否相等
     *
     * @param num1
     * @param num2
     * @param def  当有空值时返回地默认值
     * @return
     */
    public static <T> boolean eq(T num1, T num2, boolean def) {
        return compare(num1, num2, def ? 0 : null) == 0;
    }

    /**
     * 比较num1是否大于num2
     *
     * @param num1
     * @param num2
     * @param def  当有空值时返回地默认值
     * @return
     */
    public static <T> boolean gt(T num1, T num2, boolean def) {
        return compare(num1, num2, def ? null : -1) > 0;
    }

    /**
     * 比较num1是否大于等于num2
     *
     * @param num1
     * @param num2
     * @param def  当有空值时返回地默认值
     * @return
     */
    public static <T> boolean gte(T num1, T num2, boolean def) {
        return compare(num1, num2, def ? null : -1) >= 0;
    }

    /**
     * 比较num1是否小于num2
     *
     * @param num1
     * @param num2
     * @param def  当有空值时返回地默认值
     * @return
     */
    public static <T> boolean lt(T num1, T num2, boolean def) {
        return compare(num1, num2, def ? null : 1) < 0;
    }

    /**
     * 比较num1是否小于等于num2
     *
     * @param num1
     * @param num2
     * @param def  当有空值时返回地默认值
     * @return
     */
    public static <T> boolean lte(T num1, T num2, boolean def) {
        return compare(num1, num2, def ? null : 1) <= 0;
    }

    /**
     * 数据转换
     *
     * @param p      传数据
     * @param clz    返回数据类型
     * @param defVal 默认值
     * @param <R>
     * @param <P>
     * @return
     */
    public static <R extends Number, P> R parse(final P p, Class<R> clz, R... defVal) {
        if (p == null || !com.digua.atools.tools.ObjUtil.isBaseDataOrStr(p)) {
            return defVal == null || defVal.length <= 0 ? null : defVal[0];
        }
        if (com.digua.atools.tools.ObjUtil.eq(p.getClass().getSimpleName(), clz.getSimpleName())) {
            return (R) p;
        }
        try {
            Map<String, P> map = new HashMap<>();
            map.put("val", p);
            String json = com.digua.atools.tools.StrUtil.format(JSON.toJSONString(map), p);
            JSONObject jobj = JSON.parseObject(json);
            return jobj.getObject("val", clz);
        } catch (Exception e) {
            return defVal == null || defVal.length <= 0 ? null : defVal[0];
        }
    }

    public static <P> Integer parseInteger(final P p, Integer... defVal) {
        return parse(p, Integer.class, defVal);
    }

    public static <P> int parseInt(final P p, int... defVal) {
        Integer res = parseInteger(p, defVal == null || defVal.length <= 0 ? null : defVal[0]);
        return res == null ? 0 : res.intValue();
    }

    public static <P> Double parseDouble(final P p, Double... defVal) {
        return parse(p, Double.class, defVal);
    }

    public static <P> double parseDou(final P p, double... defVal) {
        Double res = parseDouble(p, defVal == null || defVal.length <= 0 ? null : defVal[0]);
        return res == null ? 0 : res.doubleValue();
    }

    public static <P> Float parseFloat(final P p, Float... defVal) {
        return parse(p, Float.class, defVal);
    }

    public static <P> float parseFlo(final P p, float... defVal) {
        Float res = parseFloat(p, defVal == null || defVal.length <= 0 ? 0 : defVal[0]);
        return res == null ? 0 : res.floatValue();
    }

    public static <P> Long parseLong(final P p, Long... defVal) {
        return parse(p, Long.class, defVal);
    }

    public static <P> long parseLon(final P p, long... defVal) {
        Long res = parseLong(p, defVal == null || defVal.length <= 0 ? 0 : defVal[0]);
        return res == null ? 0 : res.longValue();
    }

    /**
     * 判断是否是在指定范围内(两边不能等)
     *
     * @param val 要判断的值
     * @param min 最小值
     * @param max 最大值
     * @return
     */
    public static <T extends Number> boolean isRange(T val, T min, T max) {
        return isRange(null, val, min, max, null);
    }

    /**
     * 判断是否是在指定范围内(两边能等)
     *
     * @param val 要判断的值
     * @param min 最小值
     * @param max 最大值
     * @return
     */
    public static <T extends Number> boolean isRangeEe(T val, T min, T max) {
        return isRangeEe(null, val, min, max, null);
    }

    /**
     * 判断是否是在指定范围内(前边能等)
     *
     * @param val 要判断的值
     * @param min 最小值
     * @param max 最大值
     * @return
     */
    public static <T extends Number> boolean isRangeNe(T val, T min, T max) {
        return isRangeNe(null, val, min, max, null);
    }

    /**
     * 判断是否是在指定范围内(后边能等)
     *
     * @param val 要判断的值
     * @param min 最小值
     * @param max 最大值
     * @return
     */
    public static <T extends Number> boolean isRangeEn(T val, T min, T max) {
        return isRangeEn(null, val, min, max, null);
    }

    /**
     * 判断是否是在指定范围内(两边不能等)
     *
     * @param context 上下文
     * @param val     要判断的值
     * @param min     最小值
     * @param max     最大值
     * @param errMsg  不在范围内的错误提示
     * @return
     */
    public static <T extends Number> boolean isRange(Context context, T val, T min, T max, String errMsg) {
        if (min == null && max == null) {
            return true;
        }
        if (val == null && (max != null || min != null)) {
            if (context != null && com.digua.atools.tools.StrUtil.isNotBlank(errMsg)) {
                Toast.makeText(context, errMsg, Toast.LENGTH_SHORT).show();
            }
            return false;
        }
        if (lt(min, val) || gt(max, val)) {
            return true;
        }
        if (context != null && com.digua.atools.tools.StrUtil.isNotBlank(errMsg)) {
            Toast.makeText(context, errMsg, Toast.LENGTH_SHORT).show();
        }
        return false;
    }

    /**
     * 判断是否是在指定范围内(两边能等)
     *
     * @param context 上下文
     * @param val     要判断的值
     * @param min     最小值
     * @param max     最大值
     * @param errMsg  不在范围内的错误提示
     * @return
     */
    public static <T extends Number> boolean isRangeEe(Context context, T val, T min, T max, String errMsg) {
        if (min == null && max == null) {
            return true;
        }
        if (val == null && (max != null || min != null)) {
            if (context != null && com.digua.atools.tools.StrUtil.isNotBlank(errMsg)) {
                Toast.makeText(context, errMsg, Toast.LENGTH_SHORT).show();
            }
            return false;
        }
        if (lte(min, val) || gte(max, val)) {
            return true;
        }
        if (context != null && com.digua.atools.tools.StrUtil.isNotBlank(errMsg)) {
            Toast.makeText(context, errMsg, Toast.LENGTH_SHORT).show();
        }
        return false;
    }

    /**
     * 判断是否是在指定范围内(前边能等)
     *
     * @param context 上下文
     * @param val     要判断的值
     * @param min     最小值
     * @param max     最大值
     * @param errMsg  不在范围内的错误提示
     * @return
     */
    public static <T extends Number> boolean isRangeNe(Context context, T val, T min, T max, String errMsg) {
        if (min == null && max == null) {
            return true;
        }
        if (val == null && (max != null || min != null)) {
            if (context != null && com.digua.atools.tools.StrUtil.isNotBlank(errMsg)) {
                Toast.makeText(context, errMsg, Toast.LENGTH_SHORT).show();
            }
            return false;
        }
        if (lte(min, val) || gt(max, val)) {
            return true;
        }
        if (context != null && com.digua.atools.tools.StrUtil.isNotBlank(errMsg)) {
            Toast.makeText(context, errMsg, Toast.LENGTH_SHORT).show();
        }
        return false;
    }

    /**
     * 判断是否是在指定范围内(后边能等)
     *
     * @param context 上下文
     * @param val     要判断的值
     * @param min     最小值
     * @param max     最大值
     * @param errMsg  不在范围内的错误提示
     * @return
     */
    public static <T extends Number> boolean isRangeEn(Context context, T val, T min, T max, String errMsg) {
        if (min == null && max == null) {
            return true;
        }
        if (val == null && (max != null || min != null)) {
            if (context != null && com.digua.atools.tools.StrUtil.isNotBlank(errMsg)) {
                Toast.makeText(context, errMsg, Toast.LENGTH_SHORT).show();
            }
            return false;
        }
        if (lt(min, val) || gte(max, val)) {
            return true;
        }
        if (context != null && com.digua.atools.tools.StrUtil.isNotBlank(errMsg)) {
            Toast.makeText(context, errMsg, Toast.LENGTH_SHORT).show();
        }
        return false;
    }
}
